<?
/**
 * VoiceOne Settings/Plugin/create
 *
 * Frontend to provide access to the plugin system in voiceone.
 * Allows to create plugins build on installed voiceone objects like applications and macros.
 * Uses an associative array(hash) of array $state to store state of all elements that can be part of a plugin
 * Requires an associative array(hash) of array 'state' on the client (browser side) as well to store values between requests
 * Requires also a javascript function setState to set the array 'state'. This is part of xajaxExtend.js
 * The page is divided in areas using DIV elements. These areas are enabled/disabled via xajax,
 * to get a userexperiences of several pages.
 * Messages are written into DIV elements via xajax, thus avoiding classic post/get via forms
 * @author Wolfgang Alper
 * @package voiceone
 * @subpackage settings_plugin
 * @todo Add unique constants for all voiceone objects
 * @todo Add more elements to plugin creation
 */

include ("../../../admin/config/cfg.php");
global $cwlang, $cwLanguage, $absBasePath;
require_once("$absBasePath/lib/xajax/xajax.inc.php");

// ************************************ xajax functions start ************************************


/**
 * Custom Response Class to extend xajaxResponse
 * 
 * Adds support to add/remove elements in select elements
 * Requires Javascriptcode for "addOption" and "removeAllOptions"
 */
class customXajaxResponse extends xajaxResponse {  

  // make life easier to add options to select element
  function addCreateOption($sSelectId, $sOptionId, $sOptionText, $sOptionValue) {
  
    $this->addScript( "addOption('" . $sSelectId . "','" . $sOptionId . "','" . $sOptionText . "','" . $sOptionValue . "');" );
  }

  // allow to remove all options from a select element
  function addRemoveAllOptions($sSelectId) {
  
    $this->addScript( "removeAllOptions('" . $sSelectId . "');" );
  }
}

// ===================== xajax support functions start ==============================

/**
 * Show an alert / info message on in a specific DIV by enabling that div
 *
 * @param integer $type defined as constant. Can be GOOD or BAD
 * @param string $div ID of DIV element
 * @param string $msg content that is written to the innerHTML attribute
 * @return xajax getXML
 */
function setAlert($type, $msg="alertInfo", $div) {

  $objResponse = new xajaxResponse();
  
  switch ($type) {
    case GOOD:
      $style = "AlertGood";
    break;
    
    case BAD:
      $style = "AlertBad";
    break;
  }
  
  $objResponse->addAssign($div, "className", $style);
  $objResponse->addAssign($div, "style.display", "");
  $objResponse->addAssign($div, "innerHTML", $msg);
  
  return $objResponse->getXML(); 
}



/**
 * Switch to an area (DIV) by enableing that DIV and disabling all others
 *
 * Allows to simulate several pages without loading anything
 * @param string $area ID of DIV element to switch to
 * @return xajax getXML
 */
function switchToArea($area) {

  $objResponse = new xajaxResponse();

  switch ($area) {
    case "pluginInfoSection":
      $objResponse->addAssign("pluginInfoSection", "style.display", "");
      $objResponse->addAssign("pluginBuildSection", "style.display", "none");
    break;
 
    case "pluginBuildSection":
      $objResponse->addAssign("pluginInfoSection", "style.display", "none");
      $objResponse->addAssign("pluginBuildSection", "style.display", "");
    break;
  }

  return $objResponse->getXML();
}

// ===================== xajax support functions end ===============================

// ===================== xajax main functions start =================================
/**
 * xajax - Update Elements in browser depending on their value in array $state
 * 
 * Expects a javascript array "state" on the browser to pass the state between the browser and php between requests
 * Uses xajax to enable or disable options in select select boxes as part of the array.
 * Example: $state['app]['31']['value']="selected"; $state['app]['31']['name']="option name";
 * The select element in the browser must have an ID like: TYPE-STATE i.e. MACRO-STATE_AVALIABLE
 * @param array $state including all elements
 * @return xajax getXML
 */ 
function updatePluginElements($state) {

  $objResponse = new customXajaxResponse();
  
  //structure: $state['app]['31']['value']="selected"; $state['app]['31']['name']="My option name"; 
  foreach ($state as $mysec=>$myopt) {
    // clear all select boxes
    $objResponse->addRemoveAllOptions($mysec.'-'.STATE_AVAILABLE);
    $objResponse->addRemoveAllOptions($mysec.'-'.STATE_SELECTED);
    $objResponse->addRemoveAllOptions($mysec.'-'.STATE_AUTOSELECTED);  
    // disable autoselect to show the user that he cannot do anything here
    $objResponse->addAssign($mysec.'-'.STATE_AUTOSELECTED, 'disabled', true); 

    // add elements depending on their state
    foreach ($myopt as $myid=>$myval) {
      $objResponse->addCreateOption($mysec.'-'.$myval['value'], $mysec.'-'.$myid, $myval['name'], $myid);
    }
  
  }

  // update global state on the client
  $objResponse->addScriptCall("setState", $state);

  return $objResponse->getXML();
}


/**
 * xajax - Init page of plugin creation. 
 *
 * Hide/Show div elements and populate elements with defaults
 * The plugin creator uses more than one div to give the user the feeling of more pages.
 * The divs organize logical sections for user input.
 * @return xajax getXML
 * @see updatePluginElements
 */
function initPage() {

  global $asterisk, $cwlang;

  // need to use here only one time, because initPage sets the array "state" in the browser via javascript
  $state = array();

  $objResponse = new customXajaxResponse();

  // enable the base view and disable the build view
  $objResponse->addAssign("pluginInfoSection", "style.display", "");
  $objResponse->addAssign("pluginBuildSection", "style.display", "none");
  $objResponse->addAssign("alertInfo", "className", "AlertGood");
  $objResponse->addAssign("alertInfo", "style.display", "none");
  $objResponse->addAssign("alertInfo", "innerHTML", "");

  // check preferences
  // check if "which", "zip" and "unzip" are installed
  $msg = "";
  $ret = shell_exec("which which");
  if ($ret == "") {$msg = "Missing cmd WHICH on the system.<br />";}
  $ret = shell_exec("which zip");
  if ($ret == "") {$msg .= "Missing cmd ZIP on the system.<br />";}
  $ret = shell_exec("which unzip");
  if ($ret == "") {$msg .= "Missing cmd UNZIP on the system.<br />";}
  
  if ($msg != "") {
    $msg = "Plugin creation will not work!<br />" . $msg;
    $objResponse->loadXML(setAlert(BAD, $msg, "alertInfo"));
  }

  
  // add installed plugins to list and empty entry as default 
  // this is slightly diffrent from all other options
  // it should only allow the user to build a new plugin based on an existing one
  $section = "pluginBase"; // no constant available
  $objResponse->addCreateOption($section, $section."-00", $cwlang["plugins"]["pluginBaseEmpty"], "00");
  $list=$asterisk->getPlugin("");
  foreach ($list as $item) {
    $objResponse->addCreateOption($section, $section."-".$item['id'], $item['name'], $item['id']);
  }

  // now we populate the entities that can be selected to build a new plugin. 
  
  // add installed apps to list
  $section = APPLICATION;
  $list=$asterisk->getApplication("");
  if (is_array($list)) {
    foreach ($list as $item) {
      $state[$section][$item['id']]['value']=STATE_AVAILABLE; 
      $state[$section][$item['id']]['name']=$item['name'];
    }
  }

  // add installed macros to list
  $section = MACRO;
  $list=$asterisk->getMacro("");
  if (is_array($list)) {
    foreach ($list as $item) {
      $state[$section][$item['id']]['value']=STATE_AVAILABLE; 
      $state[$section][$item['id']]['name']=$item['name'];
    }
  }

  // add installed queues to list
  $section = QUEUE; 
  $list=$asterisk->getQueue("");
  if (is_array($list)) {
    foreach ($list as $item) {
      $state[$section][$item['id']]['value']=STATE_AVAILABLE; 
      $state[$section][$item['id']]['name']=$item['name'];
    }
  }

//**** not implemented start ****
/*
  // add installed IVR to list  
  $section = "ivr"; // no entity defined so far
  $list=$asterisk->getIvr("");
  foreach ($list as $item) {
    $state[$section][$item['id']]['value']=STATE_AVAILABLE; 
    $state[$section][$item['id']]['name']=$item['name'];
  }


  // add installed audiofiles to list
  $section = "audioFile"; // no entity defined so far
  $list=$asterisk->getAudioFile();
  foreach ($list as $item) {
    $state[$section][$item['id']]['value']=STATE_AVAILABLE; 
    $state[$section][$item['id']]['name']=$item['name'];
  }


  // add installed groups to list. Need to specify type as defined in constants.php. 
  // Includes Metagroups because API does not allow to pass a selector to function.
  $section = "groupExt"; // no entity defined so far
  $list=$asterisk->getGroup("", GROUP_OF_EXTENSION);
  foreach ($list as $item) {
    $state[$section][$item['id']]['value']=STATE_AVAILABLE; 
    $state[$section][$item['id']]['name']=$item['name'];
  }
  
*/

//**** not implemented end ****

  // update elements on the clients browser and also update array "state" on the client
  $objResponse->loadXML(updatePluginElements($state));

  return $objResponse->getXML();
}


/**
 * xajax - User confirms a plugin to be used as base
 * 
 * All entities that are part of the plugin will be selected.
 * All other entities will be set to available
 * @param array $state current state of all elements
 * @param array $option plugin user has selected
 * @return xajax getXML
 * @see updatePluginElements
 * @todo implement autoselect
 * @todo when modifying make sure to add entities to the exception list in the function
 */
function selectPluginBase($state, $option) {

  global $asterisk;
  
  $objResponse = new customXajaxResponse();
  
  // Reset alertinfo in case it is set
  $objResponse->addAssign("alertInfo", "style.display", "none");
  $objResponse->addAssign("alertInfo", "innerHTML", "");
   
  if ($option['value'] != '00') {
    // user selected an existing plugin
    $entities = $asterisk->getPluginEntities($option['value']);    
  } else {
    // user selected "empty" plugin so we create an empty list
    $entities = array();
  }
  
  // walk through the state array to see which elements to enable or disable depending on the selected plugin
  foreach ($state as $mysec=>$myopt) { 
    // need to check wether the section is appropriate, because we _might_ not  have unique id's
    if (($mysec != APPLICATION) and ($mysec != MACRO) and ($mysec != QUEUE)) { continue;}
   
    foreach ($myopt as $myid=>$myval) {
      // reset the element to available
      $state[$mysec][$myid]['value'] = STATE_AVAILABLE; 
      foreach ($entities as $eKey=>$eVal) {
        if ($myid == $eVal['entity_id']) { $state[$mysec][$myid]['value'] = STATE_SELECTED; } 
      }
    }
  }
  
  // update elements on the clients browser and also update array "state" on the client
  $objResponse->loadXML(updatePluginElements($state));
  
  return $objResponse->getXML();
}


/**
 * xajax - User adds or removes an entity
 * 
 * @param array $state current state of all elements
 * @param array $option plugin user has selected
 * @see updatePluginElements
 * @return xajax getXML
 * @todo implement autoselect
 */
function handleUserRequest($state, $cmd, $section, $option) {

  global $cwlang;

  $objResponse = new customXajaxResponse();

  // if user has not made a selection tell him about
  if ($option['text'] == "") {
    $objResponse->addAlert($cwlang["plugins"]["selectOptionfromLists"]);
    return $objResponse->getXML();
  }

  // what command to process...
  switch ($cmd) {
    case "add": 
      $state[$section][$option['value']]['value']=STATE_SELECTED;
    break;

    case "remove":
      $state[$section][$option['value']]['value']=STATE_AVAILABLE;
    break;
  }

  // update elements on the  clients browser   and also update $state on the client
  $objResponse->loadXML(updatePluginElements($state));

  return $objResponse->getXML();
}

/**
 * xajax - create the plugin 
 *
 * A plugin is an zip-archive and consist of the following files:
 * plugininfo.xml: = REQUIRED - plugin description file
 * plugindata.xml: OPTIONAL - plugin elements that are non-files like scripts or audiofiles
 * any number of files: OPTIONAL - scripts and/or audiofiles etc.
 * The plugin name is build like: pluginname.version
 * @param array $state contains the state of all elements (not limited to entities!)
 * @param array $formdata contains form data like author, version etc. (must match the names as used in plugin information)
 * @return xajax getXML
 */
function createPlugin($state, $formdata) {
  
  global $asterisk;
  $objResponse = new xajaxResponse();
  
  // counter
  $entities = array();
  // plugin data 
  $pld = array(); 

  // walk through the state array to see which elements to add to the plugin
  // add only elements that are selected or autoselected
  foreach ($state as $mytype=>$myopt) {  

    foreach ($myopt as $myid=>$myval) {
      
      // check wether the entity should be added to the plugin
      if (($state[$mytype][$myid]['value'] == STATE_SELECTED) or ($state[$mytype][$myid]['value'] == STATE_AUTOSELECTED)){
        
        // add id to list of entities
        $entities[] = $myid;
        switch ($mytype) {
            case APPLICATION:
              $pld[APPLICATION][] = $myid;
            break;
            
            case MACRO:
              $pld[MACRO][] = $myid;
            break;
            
            case QUEUE:
              $pld[QUEUE][] = $myid;
            break;
            default:
            break;
        } //switch
          
      } // if 
      
    } // foreach $myopt
  } // foreach section

  // check if user has selected at least one element
  if (count($entities) == 0) {
    $msg = "Creation of Plugin failed. There are no elements to add to the plugin. Please select at least one element.";
    $objResponse->loadXML(setAlert(BAD, $msg, "alertInfo"));
    // jump to top
    $objResponse->addScript("scroll(0,0);");
    
    return $objResponse->getXML();
  }
  
  // create a pluginCache with the info and data part of the plugin
  $plugin = createPluginCache($formdata, $pld);
  if ($plugin == "") {
    $msg = "Creation of Plugin failed. Please check permissions for sandbox and plugin directory.";
    $objResponse->loadXML(setAlert(BAD, $msg, "alertInfo"));
  }
  
  // create the pluginArchive and get the md5sum
  $md5sum = createPluginArchive($plugin);
  // check if the creation of the new pluginpackage was successful
  if ($md5sum != "") {
    // display alertInfo OK and offer download
    $ret = readPluginArchiveURL($plugin);
    $plURL = $ret[$plugin];
    
    $msg = "<strong>" . "Plugin created successful" . "</strong>" . "<br />" ;
    $msg .= "<strong>" . "MD5 Checksum: " . "</strong>" . $md5sum. "<br />" ;
    $msg .= "<strong>" ."Number of elements: " . "</strong>" . count($entities) . "<br />";
    $msg .= "<strong>" . "Download plugin: " . "</strong>" . "<a href=\"" . $plURL . "\">" . $plugin . "</a>";
    $objResponse->loadXML(setAlert(GOOD, $msg, "alertInfo"));
  } else {
    // display alertInfo ERR
    $msg = "Creation of Plugin failed. Please check if cmd WHICH, ZIP and UNZIP are available on the system.";
    $objResponse->loadXML(setAlert(BAD, $msg, "alertInfo"));
  }
  
  // jump to top
  $objResponse->addScript("scroll(0,0);");
  
  return $objResponse->getXML();
}


// ===================== xajax main functions end ===============================

// xajax init and registry of functions
$xajax = new xajax();
//$xajax->debugOn();

$xajax->registerFunction("setAlert"); // set Alert and Info Messages
$xajax->registerFunction("updatePluginElements"); // update browser gui elements and state array
$xajax->registerFunction("initPage"); // fill options of elements to build a plugin of
$xajax->registerFunction("selectPluginBase"); // handler if user selects a new plugin as base
$xajax->registerFunction("handleUserRequest"); // handle user interaction. i.e. add/remove an element. 
$xajax->registerFunction("switchToArea"); // switch to an area(DIV element) and disable others
$xajax->registerFunction("createPlugin"); // the "save" button. Build the plugin and do cleanup 

$xajax->processRequests();

// *********************************** xajax functions end ***********************************


//================ PAGE LOGIC ================

/**
 * Print the a section of the pluginbuilder for a specific entitiy/type
 *
 * entity or types can be any voiceone objects like apps, macros, queues etc.
 * @param string $section the entity or type for this section. This must match the definition of initPage()
 * @param string $title the headline for this section
 * @see initPage()
 */
function printPluginBuilderSection($section, $title)
{

  $availableId=$section."-".STATE_AVAILABLE;
  $selectedId=$section."-".STATE_SELECTED;
  $autoSelectedId=$section."-".STATE_AUTOSELECTED;
  
  // use heredoc to avoid escaping...
  $ret= <<<EPB
    <h2>$title</h2>
    <div class="block">
      <table>
        <tr>
          <td class="required">
            <p>Available</p>
            <select size="7" id="$availableId" name="$availableId" STYLE="width: 200px"></select>
          </td><td>
            <input type="button" value="Add >>" onclick="xajax_handleUserRequest(state, 'add', '$section', getSelectedElement('$availableId')); return false;" style="width:100px" /><br />
            <input type="button" value="<< Remove" onclick="xajax_handleUserRequest(state, 'remove', '$section', getSelectedElement('$selectedId')); return false;" style="width:100px" /><br />
          </td><td class="required">
            <p>Selected</p>
            <select size="4" id="$selectedId" name="$selectedId" STYLE="width: 200px"></select>
            <p>Autoselected</p>
            <select size="2" id="$autoSelectedId" name="$autoSelectedId" STYLE="width: 200px"></select>
          </td>
        </tr>
     </table>
  </div>
EPB;

  echo $ret;   
}



//================ MAIN CONTENTS ================
  ob_start();
  $sel="create"; include("../navigation.php");
  $xajax->printJavascript("../../../admin/lib/xajax/");    
  ?>
  
  <!-- add javascript xajax helper functions -->
  <script type="text/javascript" src="../../../admin/lib/xajaxextend/xajaxextend.js"></script>

  <!-- show AlertGood or AlertBad type messages via xajax. Default is not-visible -->
  <div id="alertInfo" style="display: none"></div>

  <div class="SectionHeader"><h1><?=$cwlang["plugins"]["titleCreate"]?></h1></div>
  <div id="basic_form">

    <!-- ================= PART1: Plugin Information  Section =================  -->
    <div id="pluginInfoSection">
    <form name="createPlugin" id="createPlugin">
      <h2>Details of new Plugin</h2>
      
      <table>
        <tr>
          <td>
            <p class="blockintro">Information about the new plugin</p>
            <div class="block">
              <dl>
                <dt class="required"><label for="label">Label:</label></dt>
                <dd><input type="text" size="40" maxlength="100" id="date" name="label" value="My-label" /></dd>
                <dt class="required"><label for="version">Version:</label></dt>
                <dd><input type="text" size="10" maxlength="20" id="version" name="version" value="My-version" /></dd>
                <dt class="required"><label for="description">Description:</label></dt>
                <dd><textarea id="description" name="description" style="width: 500px">My-description</textarea></dd>
              </dl>
            </div> 
          </td>
        </tr>
      </table>
      
      <table>
        <tr>
          <td>
            <p class="blockintro">Information about the author</p>
            <div class="block">
              <dl>
                <dt class="required"><label for="authorName">Name:</label></dt>
                <dd><input type="text" size="40" maxlength="100" id="authorName" name="authorName" value="My-name" /></dd>
                <dt class="required"><label for="authorEmail">Email:</label></dt>
                <dd><input type="text" size="40" maxlength="100" id="authorEmail" name="authorEmail" value="My-email" /></dd>
                <dt class="required"><label for="authorWebsite">Website:</label></dt>
                <dd><input type="text" size="40" maxlength="250" id="authorWebsite" name="authorWebsite" value="My-website" /></dd>
              </dl>
            </div>
          </td>
          <td>
            <p class="blockintro">Information about the system</p>
            <div class="block">
              <dl>
                <dt class="required"><label for="date">Date:</label></dt>
                <dd><input type="text" size="10" maxlength="10" id="date" name="date" value="<?=date("Y-m-d");?>" READONLY /></dd>
                <dt class="required"><label for="voVersion">VO-System:</label></dt>
                <dd><input type="text" size="10" maxlength="20" id="voVersion" name="voVersion" value="<?=$cw_version?>" READONLY /></dd>
                <dt class="required"><label for="voPlVersion">Pl-System:</label></dt>
                <dd><input type="text" size="10" maxlength="20" id="voPlVersion" name="voPlVersion" value="<?=$cw_plugin_version?>" READONLY /></dd>
              </dl>
            </div> 
          </td>
        </tr>
      </table>

      <div class="action">
        <input type="image" src="<?=$relBasePath?>/public/img/<?=$cwLanguage?>/b-cancel.gif" alt="Cancel" onclick="location.href='../'; return false;"/>
        <input type="image" src="<?=$relBasePath?>/public/img/<?=$cwLanguage?>/b-next.gif" alt="Next" onclick="xajax_switchToArea('pluginBuildSection'); return false;"/>
      </div>

    </form>
    </div>
    <!-- Form stops here. The following selections are handeled via jajavscript variable through ajax.-->
    
    

    <!-- =================  PART2: Plugin Build Section =================  -->
    <!-- Should not be visible when the page starts -->
    <div id="pluginBuildSection">

      <!-- Autoselect Section -->
<!--
      <h2>Autoselect options for the new plugin</h2>
      <p class="blockintro">Select which type of VoiceOne Objects should be autoselected if required</p>
      <div class="block">
        <table>
          <tr>
            <td>
              <input type="checkbox" id="asApp" name="asOption[app]" /><label for="asApp">Applications</label><br />
              <input type="checkbox" id="asIVR" name="asOption[ivr]" /><label for="asIVR">IVRs</label><br />
              <input type="checkbox" id="asAudioFile" name="asOption[audioFile]" /><label for="asAudioFile">Audiofiles</label><br />
            </td>
            <td>
              <input type="checkbox" id="asMacro" name="asOption[macro]" /><label for="asMacro">Macros</label><br />
              <input type="checkbox" id="asAGI" name="asOption[agi]" /><label for="asAGI">AGIs</label><br />
              <input type="checkbox" id="asQueue" name="asOption[queue]" /><label for="asQueue">Queues</label><br />
              <input type="checkbox" id="asGroupExt" name="asOption[groupExt]" /><label for="asGroupExt">Groups of Extensions</label><br />
            </td>
          </tr>
        </table>
      </div>
-->

      <!-- Base selection: build from scratch or based on existing plugin -->
      <h2>Where to build the new plugin from</h2>
      <p class="blockintro">Select an existing plugin or start with an empty set of objects.</p>
      <div class="block">
        <dl>
          <dt class="required">Plugin Base:</dt>
          <dd>
             <select size="1" id="pluginBase" name="pluginBase"></select>
             <input type="button" value="Build Plugin Base" onclick="xajax_selectPluginBase(state, getSelectedElement('pluginBase')); return false;"/><br />
          </dd>
          
        </dl>
      </div>  


      <!-- Application Section -->
      <?=printPluginBuilderSection(APPLICATION, "Which Applications to add to the plugin?")?>

      <!-- Macro Section -->
      <?=printPluginBuilderSection(MACRO, "Which Macros to add to the plugin?")?>

      <!-- Queue Section -->
      <?=printPluginBuilderSection(QUEUE, "Which Queues to add to the plugin?")?>  

      <!-- IVR Section -->
      <?//=printPluginBuilderSection('ivr', "Which IVRs to add to the plugin?")?>

      <!-- Audiofile Section -->
      <?//=printPluginBuilderSection('audioFile', "Which Audiofile to add to the plugin?")?>

      <!-- Group Extensions Section -->
      <?//=printPluginBuilderSection('groupExt', "Which Groups of Extensions to add to the plugin?")?>  


      <!-- Save / Cancel -->  
      <div class="action">
        <input type="image" src="<?=$relBasePath?>/public/img/<?=$cwLanguage?>/b-prev.gif" alt="Back" onclick="xajax_switchToArea('pluginInfoSection'); return false;"/>
        <input type="image" src="<?=$relBasePath?>/public/img/<?=$cwLanguage?>/b-save.gif" alt="Save" onclick="xajax_createPlugin(state, xajax.getFormValues('createPlugin')); return false;"/>
      </div>

    </div>

  </div>



  <?
  $contents=ob_get_contents();
  ob_end_clean();

  //================ SIDEBAR ================
  ob_start(); 
  ?>
  <div class="Sidebar">
    <h1><?=$cwlang["plugins"]["sidebarTitleCreate"]?></h1>
    <p><?=$cwlang["plugins"]["sidebarTextCreate"]?></p>
  </div>
  <?  
  $sidebar=ob_get_contents();
  ob_end_clean();
  
  //================ SETTINGS ================

  $smarty->assign("section", "plugin");
  $smarty->assign("subsection", "");
  $smarty->assign("templateType", "TwoColLeft");  //OneCol, TwoColLeft, TwoColRight
  $smarty->assign("contents", $contents);
  $smarty->assign("sidebar", $sidebar);
  $smarty->display('settings.tpl');
  ?>
  <!--  Init Page via xajax call -->
  <script>xajax_initPage()</script>
  
